0000 目录
这个阶段搞了很多和Android文件权限相关的问题,虽然一知半解,但也算是对Android权限机制有一些自己的理解。遂将这些内容整理出来。因为权限这部分涉及到的内容很多,故将知识分为几块内容分别去整理。目前能想到的概要如下(现在因为进度原因有些修改):
- Android 权限底层实现原理概述
- Android 权限系统一
- Android uid,gid的生成与权限机制的联系
- Android packageManagerService与权限的千丝万缕(源码解析)
- Android 从recovery模式下的OTA升级理解权限
- Android ROOT 原理
- Android 签名
- Android 权限大杀器 — Selinux的策略
这是第一篇。2,3,4已经有一些草稿了,但离发出来还有一些时间。5,6,7还在规划中。可以关注新弄的公众号softard,后面比较完善的文章都会在这个号上及时更新。当然一些普通的随笔还是在wossoneri.github.io的博客更新。
0001 Overview
Linux File Permission
众所周知,Android的内核是linux的内核。对于linux来说,系统的一切都是文件。同时,linux为文件系统设计了一套完善的权限机制。下面简单提一下linux文件权限的核心:
比如在Android手机adb shell下查看一个目录
# ls -ld data/data/
drwxrwx--x 113 system system 4096 1970-01-01 15:08 data/data/
其中,drwxrwx--x
这10位代表文件权限,第一位文件类型可以忽略(这里类型是文件夹),后面每三位代表文件拥有的权限,包括rwx(可读,可写,可执行)。system system
表示文件属于system用户和属于system组。
翻译过来是,system用户对该文件拥有读写执行权限,system组对该文件拥有读写执行权限,其他用户对该文件拥有执行权限。简单来说就是771权限。
Android Permission
Permission权限是Android系统定义的一套权限机制,用于控制APP访问某个硬件设备或某个Android系统的组件。
举两个常见的例子:
- 如果你的App想要访问存储卡,你需要在你的AndroidManifest文件中使用对应的permission用于向系统请求权限 。
- 你可以给你的Activity组件加个自定义的访问权限,这样任何想启动该Activity的程序必须在它的AndroidManifest中进行权限的请求。见Android自定义权限。
那么为什么你在AndroidManifest文件请求storage权限你就可以访问设备文件?linux文件属性的权限和Permission到底是怎么联系起来的呢?下面我们来具体来讲。
0010 packages.list & packages.xml
Android开机阶段会扫描所有App,从Manifest文件中把App信息和权限存到packages.xml
和packages.list
文件中,具体的处理过程会在后面第三篇去分析。
因为文件包含所有已安装应用的信息,所以我们尝试安装一个App(com.softard.test),并且查看其信息:
packages.list
com.softard.test 10052 1 /data/user/0/com.softard.test default none
这里10052是uid,至于其怎么生成的后面第二篇再详谈。
packages.xml
然后对App做个修改,将其改成系统App并签名放到system/app/Test
下,再看这两个文件:
com.softard.test 1000 0 /data/user/0/com.softard.test platform 3009,3002,1023,1015,3003,3001,1021,1000,2002,2950,1010,1007
看到uid变成了1000,selinux从default变成platform,权限组从none变成3009,3002,1023,1015,3003,3001,1021,1000,2002,2950,1010,1007。而且应用一下子增加了一堆权限:
所以问题来了,改成系统应用后uid为什么变成1000?后面代表权限组的一串数字又都是什么?
0011 Android File Permission
android_filesystem_config.h
在Android中,所有权限的定义都在:system/core/include/private/android_filesystem_config.h
在这个头文件中定义了Android系统的一些用户,包含root用户,system用户,shell用户所对应的值等等。
/* This is the master Users and Groups config for the platform.
* DO NOT EVER RENUMBER
*/
#define AID_ROOT 0 /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_VPN 1016 /* vpn system */
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
#define AID_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_MTP 1024 /* MTP USB driver access */
#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_DBUS 1038 /* dbus-daemon IPC broker process */
#define AID_TLSDATE 1039 /* tlsdate unprivileged user */
#define AID_MEDIA_EX 1040 /* mediaextractor process */
#define AID_AUDIOSERVER 1041 /* audioserver process */
#define AID_METRICS_COLL 1042 /* metrics_collector process */
#define AID_METRICSD 1043 /* metricsd process */
#define AID_WEBSERV 1044 /* webservd process */
#define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */
#define AID_MEDIA_CODEC 1046 /* mediacodec process */
#define AID_CAMERASERVER 1047 /* cameraserver process */
#define AID_FIREWALL 1048 /* firewalld process */
#define AID_TRUNKS 1049 /* trunksd process (TPM daemon) */
#define AID_NVRAM 1050 /* Access-controlled NVRAM */
#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* The range 2900-2999 is reserved for OEM, and must never be
* used here */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999
/* The 3000 series are intended for use as supplemental group id's only.
* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
#define AID_READPROC 3009 /* Allow /proc read access */
#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */
/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
#define AID_OEM_RESERVED_2_START 5000
#define AID_OEM_RESERVED_2_END 5999
#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* first app user */
#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
#define AID_USER 100000 /* offset for uid ranges for each user */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */
从头文件定义,就知道每个权限组都是由一串数字代表的。除了数字,该文件还定义了一个结构体数组,映射数字对应的字符串:
static const struct android_id_info android_ids[] = {
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
{ "bluetooth", AID_BLUETOOTH, },
{ "graphics", AID_GRAPHICS, },
{ "input", AID_INPUT, },
{ "audio", AID_AUDIO, },
{ "camera", AID_CAMERA, },
{ "log", AID_LOG, },
{ "compass", AID_COMPASS, },
{ "mount", AID_MOUNT, },
{ "wifi", AID_WIFI, },
{ "adb", AID_ADB, },
{ "install", AID_INSTALL, },
{ "media", AID_MEDIA, },
{ "dhcp", AID_DHCP, },
{ "sdcard_rw", AID_SDCARD_RW, },
{ "vpn", AID_VPN, },
{ "keystore", AID_KEYSTORE, },
{ "usb", AID_USB, },
{ "drm", AID_DRM, },
{ "mdnsr", AID_MDNSR, },
{ "gps", AID_GPS, },
// AID_UNUSED1
{ "media_rw", AID_MEDIA_RW, },
{ "mtp", AID_MTP, },
// AID_UNUSED2
{ "drmrpc", AID_DRMRPC, },
{ "nfc", AID_NFC, },
{ "sdcard_r", AID_SDCARD_R, },
{ "clat", AID_CLAT, },
{ "loop_radio", AID_LOOP_RADIO, },
{ "mediadrm", AID_MEDIA_DRM, },
{ "package_info", AID_PACKAGE_INFO, },
{ "sdcard_pics", AID_SDCARD_PICS, },
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
{ "logd", AID_LOGD, },
{ "shared_relro", AID_SHARED_RELRO, },
{ "dbus", AID_DBUS, },
{ "tlsdate", AID_TLSDATE, },
{ "mediaex", AID_MEDIA_EX, },
{ "audioserver", AID_AUDIOSERVER, },
{ "metrics_coll", AID_METRICS_COLL },
{ "metricsd", AID_METRICSD },
{ "webserv", AID_WEBSERV },
{ "debuggerd", AID_DEBUGGERD, },
{ "mediacodec", AID_MEDIA_CODEC, },
{ "cameraserver", AID_CAMERASERVER, },
{ "firewall", AID_FIREWALL, },
{ "trunks", AID_TRUNKS, },
{ "nvram", AID_NVRAM, },
{ "dns", AID_DNS, },
{ "dns_tether", AID_DNS_TETHER, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
{ "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
{ "net_admin", AID_NET_ADMIN, },
{ "net_bw_stats", AID_NET_BW_STATS, },
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
{ "readproc", AID_READPROC, },
{ "wakelock", AID_WAKELOCK, },
{ "everybody", AID_EVERYBODY, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};
好了,了解这个文件我们再来看我们应用的信息:
com.softard.test 1000 0 /data/user/0/com.softard.test platform 3009,3002,1023,1015,3003,3001,1021,1000,2002,1010,1007
我们把数字对应的信息截取下来:
#define AID_SYSTEM 1000 "system" /* system server */
#define AID_LOG 1007 "log" /* log devices */
#define AID_WIFI 1010 "wifi" /* wifi subsystem */
#define AID_SDCARD_RW 1015 "sdcard_rw" /* external storage write access */
#define AID_GPS 1021 "gps" /* GPS daemon */
#define AID_MEDIA_RW 1023 "media_rw" /* internal media storage write access */
#define AID_DIAG 2002 "diag" /* access to diagnostic resources */
#define AID_NET_BT_ADMIN 3001 "net_bt_admin"/* bluetooth: create any socket */
#define AID_NET_BT 3002 "net_bt" /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 "inet" /* can create AF_INET and AF_INET6 sockets */
#define AID_READPROC 3009 "readproc" /* Allow /proc read access */
所以,当我指定应用为系统应用时,就将uid指定为了1000。并且拥有了各种属于系统的权限组。
那么,指定系统应用后是怎么获得这一系列的gid呢?这一块源码流程很多,放到后面集中分析。
好了,现在我们了解system/core/include/private/android_filesystem_config.h
文件定义以后,其实就前进了一大步。注意一下代码所在源码位置,位于system/core
下,其实它已经是Android内核部分了,所以后面涉及到权限内容,都会导入这个头文件。
现在来看一段源码再来熟悉一下这部分内容:
FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
这是位于frameworks/base/services/core/java/com/android/server/pm/Settings.java
的一段代码,功能就是创建packages.list
文件。从函数名称和参数可以知道,它是给文件添加权限的,通过这段代码可以推测出:它给packages.list文件赋予了0640的权限,权限隶属于system,权限组为package_info。
然后我们进入系统看一看是不是这样:
/data/system # ls -l packages.list
-rw-r----- 1 system package_info 13627 1970-01-01 11:27 packages.list
有没有发现原来Android底层权限其实也不是很难理解嘛?
这时,又有一个问题了,创建文件你可以这样设定权限,但系统文件/文件夹的默认权限又是从哪来的?这就要引入另外一个文件了。
fs_config.c
写过Android App的你肯定知道,App的一些数据都放在/data/data
目录下。正常情况下这个目录是不可以访问的:
/data/data $ ls
ls: .: Permission denied
我们看一下这个目录的权限:
/data/data $ ls -ld
drwxrwx--x 310 system system 12288 2019-01-11 09:51 .
我们作为shell用户,只有一个x权限, 当然访问不了。那如果我要给shell赋予访问权限改怎么改呢?
这就需要了解一下system/core/libcutils/fs_config.c
文件了。系统目录和文件的用户组以及权限都是在这个文件里定义的:
/* Rules for directories.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root.
*/
static const struct fs_path_config android_dirs[] = {
{ 00770, AID_SYSTEM, AID_CACHE, 0, "cache" },
{ 00500, AID_ROOT, AID_ROOT, 0, "config" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
{ 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local" },
{ 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" },
{ 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" },
{ 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64" },
{ 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" },
{ 00755, AID_ROOT, AID_ROOT, 0, "root" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin" },
{ 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
};
/* Rules for files.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root. Prefixes ending in * denotes wildcard
** and will allow partial matches.
*/
static const char conf_dir[] = "/system/etc/fs_config_dirs";
static const char conf_file[] = "/system/etc/fs_config_files";
static const struct fs_path_config android_files[] = {
{ 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" },
{ 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" },
{ 00444, AID_ROOT, AID_ROOT, 0, conf_dir + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, conf_file + 1 },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
{ 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral/*" },
{ 00644, AID_APP, AID_APP, 0, "data/data/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest/tests.txt" },
{ 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" },
/* the following two files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
{ 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
/* Support FIFO scheduling mode in SurfaceFlinger. */
{ 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
};
感觉也不用多说,android_dirs[]
负责文件夹的权限配置,android_files[]
负责文件的权限配置。
从里面定义找找刚提到的/data/data
目录
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
你看,就是这么回事儿而已。如果要改成shell权限的话,只需要这样改就可以了:
{ 00771, AID_SYSTEM, AID_SHELL, 0, "data/data" },
当然,如果系统里还要添加其他目录、文件需要指定权限,只需要在这个文件里添加一行即可。
0100 Android App Permission
讲到这里,还遗留一个开头提出的问题:
为什么你在AndroidManifest文件请求storage权限你就可以访问设备文件?
0010里提到过,PackageManagerService在启动后会扫描所有已经安装的App,然后加载和解析他们的Androidmanifest文件,生成packages.list
和packages.xml
等文件。解析过程就包括了permission的解析与拦截。
frameworks/base/core/res/AndroidManifest.xml
这个文件中定义了Permission拦截规则,下面列举几个:
这里看一下protectionLevel
,normal是一般权限,即不需要动态申请,直接在Manifest里注册即可获得的权限。dangerous是敏感权限,需要动态申请告知用户才能获取的权限。signature|privileged一般是系统priv-app才拥有的权限,也就是拥有系统签名的系统应用。
他的拦截规则大概是,如果App申请了signature|privileged权限,但他是普通开发者的三方App,PMS就会将其从申请权限的列表里将该权限删除。这样你的App实际上就没有获得对应的权限了。
那么,文件属性的权限是怎么和Permission联系起来的?不出意外,系统也有一个关联文件的定义frameworks/base/data/etc/platform.xml
:
这个文件定义了所有权限所属的gid。从里面找一下READ_EXTERNAL_STORAGE
权限,emmmm,什么都没做。这是因为6.0之后存储权限变成动态,需要用户确认才可以获取权限,所以这里不作处理。动态权限这部分代码先不分析了,来看一下老版本的文件:
那明确了,READ_EXTERNAL_STORAGE
权限获取的gid是sdcard_r
,然后查看上面的文件定义,对应AID_SDCARD_R
,数值是1028。实际上在7.0上得到的是sdcard_rw
,即1015。
PMS在解析每个Permission时会根据这个文件将Permission关联的gid 加入到一个gid的数组中去,从而硬件设备所对应的设备文件就能被该应用程序访问。这块具体代码流程放到下一篇去分析。想自己跟代码的话可以从该函数看起:
private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
String[] grantedPermissions) {
for (int userId : userIds) {
grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
}
// We could have touched GID membership, so flush out packages.list
synchronized (mPackages) {
mSettings.writePackageListLPr();
}
}
回到存储权限,既然系统会根据permission给App添加合适的gid,那么我们在看下内置存储的权限为
/sdcard # ls -ld
drwxrwx--x 27 root sdcard_rw 4096 1970-01-01 18:30 .
所以获得sdcard_rw
权限组的应用才可以访问内置存储。
到此Android权限的底层实现原理简单介绍完了,不过目前这里还留有一个坑,那就是我在测试App里添加STORAGE权限后,安装到设备里,通过查看进程属性,发现:
# ps | grep softard
u0_a53 3530 638 969076 30720 binder_thr b07244fc S com.softard.test
# cat /proc/3530/status
Name: com.softard.test
State: S (sleeping)
Tgid: 3530
Pid: 3530
PPid: 638
TracerPid: 0
Uid: 10053 10053 10053 10053
Gid: 10053 10053 10053 10053
Ngid: 0
FDSize: 256
Groups: 9997 50053
Groups没有对应的gid,但是程序的确可以访问/sdcard
然后我又给App系统签名,作为系统应用放进去再看,
# ps | grep soft
system 3560 629 985352 49184 SyS_epoll_ abea53b8 S com.softard.test
# cat /proc/3560/status
Name: com.softard.test
State: S (sleeping)
Tgid: 3560
Pid: 3560
PPid: 629
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
Ngid: 0
FDSize: 256
Groups: 1000 1007 1010 1015 1021 1023 2002 2950 3001 3002 3003 3009 9997 41000
这时候Groups有sdcard_rw权限了。然后从设置里手动关掉存储权限,App无法读取文件,再次检查gid发现这个1015依旧存在。
WTF,7.0的表现跟5.0完全不一样?又是一个坑…后面抽空再填吧…
行吧,这篇概览就这样了,后面就开始从眼花缭乱的源码角度去看这一切的实现。